#include "py/builtin.h"
#include "py/runtime.h"
#include "py/obj.h"
#include "py/binary.h"
#include <stdio.h>
#include <string.h>
#include "moopi.h"

/**
 * @brief 无参数无返回值函数测试
*/
STATIC mp_obj_t moopi_say_hello()
{
    printf("Hello Micropython !\n");
    // 无返回值，但必须返回 mp_const_none
    return mp_const_none;
}
// 使用类型转换宏，将方法转换为 micrpython 对象
MP_DEFINE_CONST_FUN_OBJ_0(moopi_say_hello_obj, moopi_say_hello);

/**
 * @brief 带参数函数测试
*/
STATIC mp_obj_t moopi_say_hi(mp_obj_t name)
{
    // 通过 mp_obj_get_type 可获得参数类型，可通过与 mp_type_XXX 比较确定参数类型
    if (mp_obj_get_type(name) == &mp_type_str)
    {
        const char *n = mp_obj_str_get_str(name);
        printf("Hi %s\n", n);
    }
    else
    {
        printf("Please enter a value of string type !\n");
    }
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(moopi_say_hi_obj, moopi_say_hi);

/**
 * @brief 带返回值函数测试
 * @return 返回值必须是 mp_obj_t 类型的，基础数据类型通过 mp_obj_new_XXX 进行转换
*/
STATIC mp_obj_t moopi_add(mp_obj_t va, mp_obj_t vb)
{
    int32_t a = mp_obj_get_int(va);
    int32_t b = mp_obj_get_int(vb);
    int32_t c = a + b;
    // MP_OBJ_FROM_PTR 可有可无，为了防止报警告
    return MP_OBJ_FROM_PTR(mp_obj_new_int(c));
}
MP_DEFINE_CONST_FUN_OBJ_2(moopi_add_obj, moopi_add);

/**
 * @brief 不固定参数数量函数测试
*/
STATIC mp_obj_t moopi_sum(size_t n_args, const mp_obj_t *args)
{
    int32_t sum = 0;
    for (int i = 0; i < n_args; i++)
    {
        sum += mp_obj_get_int(args[i]);
    }
    return MP_OBJ_FROM_PTR(mp_obj_new_int(sum));
}
MP_DEFINE_CONST_FUN_OBJ_VAR(moopi_sum_obj, 0, moopi_sum);

/**
 * @brief 函数重载测试
 * @throw 如果参数数量超过 5 则通过 mp_raise_TypeError 向外抛出异常
*/
STATIC mp_obj_t moopi_average(size_t n_args, const mp_obj_t *args)
{
    
    if (n_args <= 5)
    {
        int32_t sum = 0;
        for (int i = 0; i < n_args; i++)
        {
            sum += mp_obj_get_int(args[i]);
        }
        float average = sum * 1.0f / n_args;
        return MP_OBJ_FROM_PTR(mp_obj_new_float(average));
    }
    else
    {
        mp_raise_TypeError(MP_ERROR_TEXT("function expected at most 5 arguments"));
    }
}
MP_DEFINE_CONST_FUN_OBJ_VAR(moopi_average_obj, 2, moopi_average);

/**
 * @brief 不定参数数量函数测试
 * 与上一个函数定义方法相同，但转换函数不同
 * 
*/
STATIC mp_obj_t moopi_max(size_t n_args, const mp_obj_t *args)
{
    int32_t max = 0x80000000;
    for (int i = 0; i < n_args; i++)
    {
        int32_t num = mp_obj_get_int(args[i]);
        max = num>max?num:max;
    }
    return MP_OBJ_FROM_PTR(mp_obj_new_int(max));
}
// 使用这个宏转换，将锁定函数数量区间
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(moopi_max_obj, 2, 5, moopi_max);

/**
 * @brief 根据字典传值函数测试
*/
STATIC mp_obj_t moopi_achieve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args){
    // 字典 key 值枚举
    enum {ARG_name, ARG_score};
    // 定义字典取值模板
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_name, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
        { MP_QSTR_score, MP_ARG_INT, {.u_int = 0} },
    };
    // 生命字典取值数组
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    // 解析字典
    mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);

    char res[200];
    sprintf(res,"%s's score is %d .", args[ARG_name].u_obj==MP_OBJ_NULL?"":mp_obj_str_get_str(args[ARG_name].u_obj), args[ARG_score].u_int);
    return MP_OBJ_FROM_PTR(mp_obj_new_str(res,strlen(res)));
}
MP_DEFINE_CONST_FUN_OBJ_KW(moopi_achieve_obj, 0, moopi_achieve);

static uint32_t width=0,height=0;
/**
 * @brief 根据参数数量重载函数的测试
*/
STATIC mp_obj_t moopi_size(size_t n_args, const mp_obj_t *args){
    if(n_args==1){
        width = height = mp_obj_get_int(args[0]);
    }else if(n_args==2){
        width = mp_obj_get_int(args[0]);
        height = mp_obj_get_int(args[1]);
    }
    mp_obj_t res[2] = {
        mp_obj_new_int(width),
        mp_obj_new_int(height),
    };
    return MP_OBJ_FROM_PTR(mp_obj_new_tuple(2,res));
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(moopi_size_obj, 0, 2, moopi_size);

static int32_t x=0,y=0;
/**
 * @brief 根据类型重载函数的测试
*/
STATIC mp_obj_t moopi_location(size_t n_args, const mp_obj_t *args){
    if(n_args==1){
        const mp_obj_type_t *type = mp_obj_get_type(args[0]);
        if(type == &mp_type_int){
            x = y = mp_obj_get_int(args[0]);
        }else if(type == &mp_type_tuple){
            mp_obj_tuple_t *t = MP_OBJ_TO_PTR(args[0]);
            if(t->len==2){
                x = mp_obj_get_int(t->items[0]);
                y = mp_obj_get_int(t->items[1]);
            }
        }else if(type == &mp_type_list){
            mp_obj_list_t *t = MP_OBJ_TO_PTR(args[0]);
            if(t->len==2){
                x = mp_obj_get_int(t->items[0]);
                y = mp_obj_get_int(t->items[1]);
            }
        }
    }else if(n_args==2){
        x = mp_obj_get_int(args[0]);
        y = mp_obj_get_int(args[1]);
    }
    mp_obj_t res[2] = {
        mp_obj_new_int(x),
        mp_obj_new_int(y),
    };
    return MP_OBJ_FROM_PTR(mp_obj_new_tuple(2,res));
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(moopi_location_obj, 0, 2, moopi_location);

// 模块的全局字典
STATIC const mp_rom_map_elem_t moopi_globals_table[] = {
    // 第一行永远是第一样，不能删除，它定义了模块的显示名称
    {MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_moopi)},

    // 模块中方法的定义
    {MP_ROM_QSTR(MP_QSTR_sayHello), MP_ROM_PTR(&moopi_say_hello_obj)},
    {MP_ROM_QSTR(MP_QSTR_sayHi), MP_ROM_PTR(&moopi_say_hi_obj)},
    {MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&moopi_add_obj)},
    {MP_ROM_QSTR(MP_QSTR_sum), MP_ROM_PTR(&moopi_sum_obj)},
    {MP_ROM_QSTR(MP_QSTR_average), MP_ROM_PTR(&moopi_average_obj)},
    {MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&moopi_max_obj)},
    {MP_ROM_QSTR(MP_QSTR_achieve), MP_ROM_PTR(&moopi_achieve_obj)},
    {MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&moopi_size_obj)},
    {MP_ROM_QSTR(MP_QSTR_location), MP_ROM_PTR(&moopi_location_obj)},

    // 模块中常量的定义
    {MP_ROM_QSTR(MP_QSTR_ROTATE_0), MP_ROM_INT(0)},
    {MP_ROM_QSTR(MP_QSTR_ROTATE_90), MP_ROM_INT(1)},
    {MP_ROM_QSTR(MP_QSTR_ROTATE_180), MP_ROM_INT(2)},
    {MP_ROM_QSTR(MP_QSTR_ROTATE_270), MP_ROM_INT(3)},

    {MP_ROM_QSTR(MP_QSTR_STR), MP_ROM_QSTR(MP_QSTR_My_string)},

    // 模块中类的定义
    {MP_ROM_QSTR(MP_QSTR_Object), MP_ROM_PTR(&moopi_type_object)},
    {MP_ROM_QSTR(MP_QSTR_Label), MP_ROM_PTR(&moopi_type_label)},
};

// 通过宏将成员字典转换成 micropython 对象
STATIC MP_DEFINE_CONST_DICT(moopi_globals, moopi_globals_table);

// 定义模块原型
const mp_obj_module_t mp_mod_moopi = {
    .base = {&mp_type_module},
    .globals = (mp_obj_dict_t *)&moopi_globals,
};

// 注册模块
MP_REGISTER_MODULE(MP_QSTR_moopi, mp_mod_moopi);